﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;
using System.ServiceModel;
using System.ServiceModel.Web;
using System.Text;
using System.Xml;
using System.Web.Services.Description;
using System.CodeDom;
using System.CodeDom.Compiler;
using System.Reflection;

namespace WsTesting
{
    // NOTE: You can use the "Rename" command on the "Refactor" menu to change the class name "WsTestingService" in code, svc and config file together.
    public class WsTestingService : IWsTestingService
    {
        /// <summary>
        /// Given a WSDL address, operation name, and parameter list, call the given
        /// service operation using the given list of parameters. 
        /// </summary>
        /// <param name="wsdlUrl">The url address that points to an WSDL file</param>
        /// <param name="operationName"></param>
        /// <param name="args"></param>
        /// <returns>Returns a string that wraps the return result</returns>
        public string WsTesting(String wsdlUrl, string operationName, string[] args)
        {
            string results = "";

            // create an xml reader to read the wsdl url
            //System.Net.WebClient web_client = new System.Net.WebClient();
            XmlTextReader xml_reader = new XmlTextReader(wsdlUrl);

            // reade the service description
            //System.IO.Stream stream = web_client.OpenRead(wsdlUrl);
            ServiceDescription service_description = ServiceDescription.Read(xml_reader);
            

            // service description importer
            ServiceDescriptionImporter importer = new ServiceDescriptionImporter();
            importer.ProtocolName = "Soap12";
            importer.AddServiceDescription(service_description, null, null);
            importer.Style = ServiceDescriptionImportStyle.Client;
            importer.CodeGenerationOptions = System.Xml.Serialization.CodeGenerationOptions.GenerateProperties;

            // compile the web service
            Assembly assembly = compile_service(importer);
            try
            {
                String service_name = service_description.Services[0].Name;

                object web_service_class = assembly.CreateInstance(service_name);

                Type type = web_service_class.GetType();

                results = (String)type.InvokeMember(operationName, BindingFlags.InvokeMethod, null, web_service_class, args);
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.Message);
            }

            return results;
        }

        /// <summary>
        /// Compiles a web service and returns the assembly
        /// </summary>
        /// <param name="importer">ServiceDescriptionImporter</param>
        /// <returns></returns>
        private Assembly compile_service(ServiceDescriptionImporter importer)
        {
            // a namespace and compile unit are needed by importer
            CodeNamespace code_namespace = new CodeNamespace();
            CodeCompileUnit code_unit = new CodeCompileUnit();

            code_unit.Namespaces.Add(code_namespace);

            ServiceDescriptionImportWarnings importWarnings = importer.Import(code_namespace, code_unit);

            // make sure there were no warnings before continuing
            if (importWarnings == 0)
            {
                // create a code dom compiler for C# code
                CodeDomProvider code_dom_compiler = CodeDomProvider.CreateProvider("CSharp");

                // Add the appropriate Dlls
                string[] references = new string[2] { "System.Web.Services.dll", "System.Xml.dll" };

                // get the parameters
                CompilerParameters parameters = new CompilerParameters(references);

                // Compile and get the results
                CompilerResults results = code_dom_compiler.CompileAssemblyFromDom(parameters, code_unit);

                if (results.Errors.Count > 0)
                {
                    foreach (CompilerError compiler_error in results.Errors)
                    {
                        String message = "Compiler Exception: " + compiler_error.ErrorNumber;
                        Console.WriteLine(message);
                    }

                    throw new Exception("Error(s) occured while compiling web service");
                }

                return results.CompiledAssembly;
            }
            else
            {
                // improperly formatted WSDL
                throw new Exception("Invalid WSDL format");
            }
        }
    }


}
